[aws-iot-device-sdk-js-v2] 試して理解する Fleet Provisioning
こんにちは、CX事業本部のうらわです。
AWS IoTにおける認証情報のプロビジョニング方法の1つであるFleet Provisioningについて、aws-iot-device-sdk-js-v2を用いて手を動かして流れを確認してみました。
環境
Macで作業します。パッケージマネージャーはyarnを使用します。途中でopensslも使用します。
aws-iot-device-sdk-js-v2
は本記事の執筆時点の最新バージョンであるv1.4.3
を利用します。
AWSのリージョンは東京リージョンです(ap-northeast-1)。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H15 $ node -v v14.15.4 $ yarn -v 1.22.10 $ openssl version LibreSSL 2.8.3
Fleet Provisioningについて
AWS IoTの認証情報のプロビジョニング方法については以下の資料にわかりやすくまとまっています。
一覧は以下となります(上記の資料より引用)。
Fleet Provisioningは、デバイスを初回接続時にAWS IoTに登録させ、AWS IoTに認証情報を発行させたい場合に有効な方法です。
流れは以下となります(上記の資料より引用)。今回は「0. デバイス側で事前に秘密鍵を持っている場合にはCSRを投げることも可能」と「1. クレーム証明書・秘密鍵を使って証明書・秘密鍵の発行をリクエスト」の両方を試してみます。
sdkをクローンする
まずはsdkを任意のディレクトリにクローンします。Fleet Provisioningのサンプルコードがあるディレクトリに移動しておきます。
git clone https://github.com/aws/aws-iot-device-sdk-js-v2.git cd samples/node/fleet_provisioning
続いて、package.json
のaws-iot-device-sdk-js-v2
のバージョンを../../../
から^1.4.3
に変更し、package-lock.json
は削除してyarn install
します。ts-node
も追加でインストールしておきます。
# 以下のディレクトリで作業します cd samples/node/fleet_provisioning rm -rf package-lock.json yarn install yarn add -D ts-node
また、Fleet Provisioningで入手する証明書を使用してAWS IoTとの疎通確認を行うためにsamples/node/pub_sub
のサンプルコードも利用します。上記と同様の手順でパッケージをインストールしておきます。
クレーム証明書・秘密鍵を作成する
Fleet Provisioningを実行するために、まずは事前にクレーム証明書と秘密鍵を作成します。これらはデバイスに埋め込まれるもので、全デバイスで共通です。
AWS IoTのメニューにて 安全性 > 証明書 > 証明書を作成する > 1-Click証明書作成(推奨) で証明書を作成し、「このモノの証明書」「公開鍵」「秘密鍵」をダウンロードしておきます。また、AWS IoTのルートCAも入手しておきます。
ダウンロードしたら「有効化」し、ここではポリシーはアタッチせず完了します。
テンプレートを作成する
AWS IoTのメニューから オンボード > フリートのプロビジョニングテンプレート を選択し、新規テンプレートを作成します。
任意のテンプレート名を設定、プロビジョニングロールの作成(名前は任意)、オプション設定の「AWS IoTレジストリを使用してデバイスフリーとを管理する」にチェックを入れます。
ポリシーを作成します。このポリシーは、Fleet Provisioningが成功すると作成された証明書に自動でアタッチされます。今回は検証用のため全てのリソースに対して全てのアクションを許可しておきます。
モノが登録される時の設定をします。今回はモノの名前プレフィックスだけ指定しておきます。Fleet Provisiningによって登録されるモノにはこのプレフィックスが自動でつきます。 それ以外はデフォルトのままとし、「テンプレートを作成」をクリックします。
最後に、先ほど作成したクレーム証明書にFleet Provisioningによって証明書作成・デバイス登録を可能にするポリシーをアタッチします。
以上でテンプレートの準備は完了です。
試す
冒頭のフローの中に記載のあった「0. デバイス側で事前に秘密鍵を持っている場合にはCSRを投げることも可能」と「1. クレーム証明書・秘密鍵を使って証明書・秘密鍵の発行をリクエスト」の2つのFleet Provisioningを、sdkのサンプルコードを用いて試します。
0はデバイスプロビジョニングMQTT APIのCreateCertificateFromCsr
、1はCreateKeysAndCertificate
が該当します。
また、sdkのサンプルコードではCreateKeysAndCertificate
またはCreateCertificateFromCsr
の実行後、続けてRegisterThing
を実行してモノの登録も実施してくれます。
各APIの詳細は以下のドキュメントを参照してください。
CreateKeysAndCertificate
このAPIではリクエストペイロードは空です。レスポンスペイロードには新しい証明書と秘密鍵が含まれます。
レスポンスの秘密鍵と証明書がファイルで欲しいため、sdkのサンプルコードにprivateKey
とcertificatePem
をファイルに書き出すコードを追加しておきます。
fs.writeFileSync( `${response.certificateId}-certificate.pem.crt`, response.certificatePem ); fs.writeFileSync( `${response.certificateId}-private.pem.key`, response.privateKey );
コードを修正したら必要なコマンドオプションを指定してFleet Provisioningを実行します。ダウンロードしておいた証明書ファイル等はindex.ts
と同じディレクトリに配置しておきます。
$ npx ts-node index.ts \ --endpoint xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com \ --ca_file AmazonRootCA1.pem \ --cert xxxxxxxxxx-certificate.pem.crt \ --key xxxxxxxxxx-private.pem.key \ --template_name my-template-20210423 \ --template_parameters '{"SerialNumber": "12345"}'
コマンドオプションについては以下の通りです。
オプション | 設定内容 |
---|---|
--endpoint | AWS IoTのエンドポイント |
--ca_file | ダウンロードしておいたAWS IoTルートCAのファイル名 |
--cert | ダウンロードしておいたクレーム証明書のファイル名 |
--key | ダウンロードしておいた秘密鍵のファイル名 |
--template_name | 先ほど作成したテンプレートの名前 |
--template_parameters | モノの名前のプレフィックス以下につける値をSerialNumber をキーにして指定(json文字列) |
実行後、カレントディレクトリに秘密鍵と証明書が作成されています。また、ブラウザで確認すると証明書とともにモノも自動で作られていることがわかります。
この証明書を使用してAWS IoTとの疎通確認を行います。AWS IoTのメニューからテストを開き、「トピックをサブスクライブする」のトピックフィルターの入力フォームにtest/topic
と入力してサブスクライブします。
samples/node/pub_sub
のサンプルコードでMQTT Publishを試します。
$ mv 証明書ファイル名 ../pub_sub $ mv 秘密鍵ファイル名 ../pub_sub # ルートCA証明書もコピーしておく $ cp AmazonRootCA1 ../pub_sub $ cd ../pub_sub $ npx ts-node index.ts \ --endpoint xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com \ --ca_file AmazonRootCA1.pem \ --cert 証明書ファイル名 \ --key 秘密鍵ファイル名 Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":1} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":2} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":3} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":4} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":5} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":6} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":7} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":8} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":9} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":10}
AWS IoTのテスト画面を確認すると、同様のメッセージが表示されます。Fleet Provisioningでモノを登録し自動で作成された証明書と秘密鍵を用いてAWS IoTとの疎通が成功したことを確認できました。
CreateCertificateFromCsr
このAPIではCSRをリクエストペイロードに含め、レスポンスペイロードに作成された新しい証明書が含まれます。
秘密鍵は手元で生成したもの(デバイスに保存される想定)を利用するため、CreateKeysAndCertificate
と異なり秘密鍵はインターネットを通りません。これは本記事の冒頭で掲載している一覧表にも記載があります。
まずは手元で秘密鍵とCSRの作成を行います。今回はopensslを使用します。
$ openssl genrsa 2048 > my-device-private.pem.key Generating RSA private key, 2048 bit long modulus # 検証用なのでCommon Name以外は全て空にする $ openssl req -new -key my-device-private.pem.key > my-device.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []: State or Province Name (full name) []: Locality Name (eg, city) []: Organization Name (eg, company) []: Organizational Unit Name (eg, section) []: Common Name (eg, fully qualified host name) []:Test Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:
CreateKeysAndCertificate
と同様、レスポンスに含まれる証明書をファイルとして保存したいため、サンプルコードを編集しておきます。
fs.writeFileSync( `certs/${response.certificateId}-certificate.pem.crt`, response.certificatePem );
Fleet Provisioningを実施する前に、クレーム証明書にアタッチしているポリシーを修正しておく必要があります。メニューの 安全性 > ポリシー から、テンプレート名-timestamp
という名前で作成されているポリシーのポリシードキュメントを編集します。
以下のハイライトされている行は追加箇所です。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "iot:Publish", "iot:Receive" ], "Resource": [ "arn:aws:iot:ap-northeast-1:account-id:topic/$aws/certificates/create/*", "arn:aws:iot:ap-northeast-1:account-id:topic/$aws/certificates/create-from-csr/*", "arn:aws:iot:ap-northeast-1:account-id:topic/$aws/provisioning-templates/my-template-20210423/provision/*" ] }, { "Effect": "Allow", "Action": [ "iot:Subscribe" ], "Resource": [ "arn:aws:iot:ap-northeast-1:account-id:topicfilter/$aws/certificates/create/*", "arn:aws:iot:ap-northeast-1:account-id:topicfilter/$aws/certificates/create-from-csr/*", "arn:aws:iot:ap-northeast-1:account-id:topicfilter/$aws/provisioning-templates/my-template-20210423/provision/*" ] } ] }
参考: https://docs.aws.amazon.com/iot/latest/developerguide/reserved-topics.html#reserved-topics-fleet
あとはコマンドオプションを指定してFleet Provisioningを実行します。CreateKeysAndCertificate
とは異なり、--csr_file
で先ほど作成したCSRのファイル名を指定する必要があります。
$ npx ts-node index.ts \ --endpoint xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com \ --ca_file AmazonRootCA1.pem \ --cert xxxxxxxxxx-certificate.pem.crt \ --key xxxxxxxxxx-private.pem.key \ --template_name my-template-20210423 \ --template_parameters '{"SerialNumber": "22222"}' \ --csr_file my-device.csr
実行後、カレントディレクトリに証明書が作成されています。CreateKeysAndCertificate
と同様に疎通確認を行います。コマンドオプションの--key
にopensslで作成した秘密鍵を指定する点が異なります。
# 保存された証明書を移動する $ mv 証明書ファイル名 ../pub_sub # opensslで作成した秘密鍵を移動する $ mv my-device-private.pem.key ../pub_sub $ cd ../pub_sub $ npx ts-node index.ts \ --endpoint xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com \ --ca_file AmazonRootCA1.pem \ --cert 証明書ファイル名 \ --key my-device-private.pem.key Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":1} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":2} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":3} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":4} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":5} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":6} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":7} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":8} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":9} Publish received. topic:"test/topic" dup:false qos:1 retain:false {"message":"Hello world!","sequence":10}
おわりに
ドキュメントを読むだけでなく、実際に手を動かすことでFleet Provisioningの流れを把握することができました。sdkのサンプルコードを利用すれば簡単に実行することができるため、ぜひ試してみてください。